//
//  CRF++ -- Yet Another CRF toolkit
//
//  $Id: node.cpp 1595 2007-02-24 10:18:32Z taku $;
//
//  Copyright(C) 2005-2007 Taku Kudo <taku@chasen.org>
//
#include <cmath>
#include "../include/node.h"
#include "../include/common.h"

namespace CRFPP {

// 计算学习率(步长)
void Node::calcAlpha() {

	/*
	 * 其中cost是我们刚刚计算的当前节点的M_i(x)，而alpha则是当前节点的前向概率。lpath是入边，如代码和图片所示，一个顶点可能有多个入边。
	 */
  alpha = 0.0;
  for (const_Path_iterator it = lpath.begin(); it != lpath.end(); ++it)
    alpha = logsumexp(alpha,
                      (*it)->cost +(*it)->lnode->alpha,
                      (it == lpath.begin()));
  alpha += cost;
}

void Node::calcBeta() {
  beta = 0.0;
  for (const_Path_iterator it = rpath.begin(); it != rpath.end(); ++it)
    beta = logsumexp(beta,
                     (*it)->cost +(*it)->rnode->beta,
                     (it == rpath.begin()));
  beta += cost;
}

/**
 * 计算节点期望
 * @param expected 输出期望
 * @param Z 规范化因子
 * @param size 标签个数
 */
void Node::calcExpectation(double *expected, double Z, size_t size) const {
  const double c = std::exp(alpha + beta - cost - Z);
  for (int *f = fvector; *f != -1; ++f) expected[*f + y] += c;
  for (const_Path_iterator it = lpath.begin(); it != lpath.end(); ++it)
    (*it)->calcExpectation(expected, Z, size);
}
}
